#pragma once
#include "Cell.h"
#include "GameObject.h"

#define CELL_SIZE 32

enum MapFlags
{
	MF_INVALID,
};

class Map : public GameObject
{
public:
	Map(void);
	~Map(void);
	
	void create(uint32 guid, const std::string& name, uint32 w, uint32 h);

	void addToMap(WorldObject* obj);
	void removeFromMap(WorldObject* obj);
 
	template<typename T>
	void visitAllObjects(T& visitor);

	template<typename T>
	void visitPlayers(T& visitor);

	template<typename T>
	void visitAllObjectsInSet(float cell_x, float cell_y, T& visitor);

	template<typename T>
	void visitPlayersInSet(float cell_x, float cell_y, T& visitor);

	void broadcastMessage(WorldObject* obj, ArrayBuffer* msg);
	void broadcastMessageToSet(WorldObject* obj, ArrayBuffer* msg);

	void reLocation(WorldObject*, float x, float y);

private:
	void handlePositionChanged(EventParams& params);
	CellPair computeCell(float x, float y);
	Cell* getCell(const CellPair& cell);

private:
	MapFlags m_flags;
	Cell** m_cells;

	int m_cell_x_num;
	int m_cell_y_num;

};

template<typename T>
void Map::visitAllObjects(T& visitor)
{
	Cell::iterator it;
	for (int x=0; x<m_cell_x_num; ++x)
		for (int y=0; y<m_cell_y_num; ++y)
		{
			it = m_cells[x][y].begin();
			while(it != m_cells[x][y].end())
			{
				if (!visitor(*it))
					return;

				++it;
			}
		}
}

template<typename T>
void Map::visitPlayers(T& visitor)
{
	Cell::player_iterator it;
	for (int x=0; x<m_cell_x_num; ++x)
		for (int y=0; y<m_cell_y_num; ++y)
		{
			it = m_cells[x][y].player_begin();
			while(it != m_cells[x][y].player_end())
			{
				if (!visitor(*it))
					return;

				++it;
			}
		}
}

template<typename T>
void Map::visitAllObjectsInSet(float cell_x, float cell_y,  T& visitor)
{
	uint32 x_start,y_start,x_end,y_end;
	CellPair cell(cell_x,cell_y);

	x_start = cell.x > 0 ? cell.x-1 : cell.x;
	y_start = cell.y > 0 ? cell.y-1 : cell.y;

	x_end = cell.x < m_cell_x_num-1 ? cell.x+1 : m_cell_x_num-1;
	y_end = cell.y < m_cell_y_num-1 ? cell.y+1 : m_cell_y_num-1;

	Cell::iterator it;
	for (uint32 x=x_start; x<x_end; ++x)
		for (uint32 y=y_start; y<y_end; ++y)
		{
			it = m_cells[x][y].begin();
			while(it != m_cells[x][y].end())
			{
				if (!visitor(*it))
					return;

				++it;
			}
		}
}

template<typename T>
void Map::visitPlayersInSet(float cell_x, float cell_y,  T& visitor)
{
	uint32 x_start,y_start,x_end,y_end;
	CellPair cell(cell_x,cell_y);

	x_start = cell.x > 0 ? cell.x-1 : cell.x;
	y_start = cell.y > 0 ? cell.y-1 : cell.y;

	x_end = cell.x < m_cell_x_num-1 ? cell.x+1 : m_cell_x_num-1;
	y_end = cell.y < m_cell_y_num-1 ? cell.y+1 : m_cell_y_num-1;

	Cell::player_iterator it;
	for (uint32 x=x_start; x<x_end; ++x)
		for (uint32 y=y_start; y<y_end; ++y)
		{
			it = m_cells[x][y].player_begin();
			while(it != m_cells[x][y].player_end())
			{
				if (!visitor(*it))
					return;

				++it;
			}
		}
}
